using System;
using System.Collections.Generic;
using ZFramework;

namespace PaintAWorld
{
    public interface ICommand
    {
        void Execute(WorldLogic world);
    }

    public class SetVoxelCommand : ICommand
    {
        public int fromX, fromY, fromZ;
        public int toX, toY, toZ;
        public uint color;

        public SetVoxelCommand(uint color, int fromX, int fromY, int fromZ, int toX, int toY, int toZ)
        {
            this.color = color;
            this.fromX = Math.Min(fromX, toX);
            this.fromY = Math.Min(fromY, toY);
            this.fromZ = Math.Min(fromZ, toZ);
            this.toX = Math.Max(fromX, toX);
            this.toY = Math.Max(fromY, toY);
            this.toZ = Math.Max(fromZ, toZ);
        }

        public SetVoxelCommand(uint color, int fromX, int fromY, int fromZ) : this(color, fromX, fromY, fromZ, fromX, fromY, fromZ) { }

        public static SetVoxelCommand Parse(string[] args)
        {
            if (args.Length < 4) return null;
            uint color;
            if (args[0].StartsWith("0x"))
            {
                color = Convert.ToUInt32(args[0][2..], 16);
            }
            else
            {
                color = uint.Parse(args[0]);
            }
            int fromX = int.Parse(args[1]);
            int fromY = int.Parse(args[2]);
            int fromZ = int.Parse(args[3]);
            if (args.Length < 7) return new SetVoxelCommand(color, fromX, fromY, fromZ);
            int toX = int.Parse(args[4]);
            int toY = int.Parse(args[5]);
            int toZ = int.Parse(args[6]);
            return new SetVoxelCommand(color, fromX, fromY, fromZ, toX, toY, toZ);
        }

        public void Execute(WorldLogic world)
        {
            List<Vec3I> batch = [];
            for (int z = fromZ; z <= toZ; z++)
            {
                for (int y = fromY; y <= toY; y++)
                {
                    for (int x = fromX; x <= toX; x++)
                    {
                        batch.Add(new(x, y, z));
                    }
                }
            }
            world.SetVoxelBatched(batch, color);
        }
    }
    
    public class RmVoxelCommand : ICommand
    {
        public int fromX, fromY, fromZ;
        public int toX, toY, toZ;

        public RmVoxelCommand(int fromX, int fromY, int fromZ, int toX, int toY, int toZ)
        {
            this.fromX = Math.Min(fromX, toX);
            this.fromY = Math.Min(fromY, toY);
            this.fromZ = Math.Min(fromZ, toZ);
            this.toX = Math.Max(fromX, toX);
            this.toY = Math.Max(fromY, toY);
            this.toZ = Math.Max(fromZ, toZ);
        }

        public static ICommand Parse(string[] args)
        {
            if (args.Length < 3) return null;
            int fromX = int.Parse(args[0]);
            int fromY = int.Parse(args[1]);
            int fromZ = int.Parse(args[2]);
            if (args.Length < 6) return new RmVoxelCommand(fromX, fromY, fromZ, fromX, fromY, fromZ);
            int toX = int.Parse(args[3]);
            int toY = int.Parse(args[4]);
            int toZ = int.Parse(args[5]);
            return new RmVoxelCommand(fromX, fromY, fromZ, toX, toY, toZ);
        }

        public void Execute(WorldLogic world)
        {
            List<Vec3I> batch = [];
            for (int z = fromZ; z <= toZ; z++)
            {
                for (int y = fromY; y <= toY; y++)
                {
                    for (int x = fromX; x <= toX; x++)
                    {
                        batch.Add(new(x, y, z));
                    }
                }
            }
            world.RemoveVoxelBatched(batch);
        }
    }
}